package org.shangrila.comm.utils;

import java.security.NoSuchAlgorithmException;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import com.sun.crypto.provider.SunJCE;

/*字符串 DESede(3DES) 加密*/ 

public class TripleDESUtil { 
    /** 
     * KEY_ALGORITHM：密钥算法 ：TripleDES与DESede一样效果
     * CIPHER_ALGORITHM：加密/解密算法/工作模式/填充方式：TripleDES与DESede/ECB/PKCS5Padding一样效果
     */  
	private static final String Algorithm = "TripleDES";
    /** 
     * 密钥填充24位 
     */  
    public static final String KEY_Padding="000000000000000000000000";  

	/**
	 * 3DES解密：使用24位密匙，不足补0
	 * @param String  	密匙（24位）
	 * @param String	密文
	 * @return String
	 */
	public static String decrypt3DES(String key, String encoded) {
		return new String(decryptMode((key + KEY_Padding).substring(0, 24).getBytes(), hex2byte(encoded)));
	}
	/**
	 * 3DES加密：使用24位密匙，不足补0
	 * @param String  	密匙（24位）
	 * @param String	明文
	 * @return String
	 */
	public static String encrypt3DES(String key, String src) {
		return byte2hex(encryptMode((key + KEY_Padding).substring(0, 24).getBytes(), src.getBytes()), "");
	}
	
	/**
	 * 3DES加密
	 * @param byte[]  	密匙
	 * @param byte[]	明文
	 * @return byte[]
	 */
	public static byte[] encryptMode(byte[] keybyte, byte[] src) {
		try {
			SecretKey deskey = new SecretKeySpec(keybyte, Algorithm); //密钥算法 ：TripleDES与DESede一样效果
			Cipher c1 = Cipher.getInstance(Algorithm);//加密/解密算法/工作模式/填充方式：TripleDES与DESede/ECB/PKCS5Padding一样效果
			c1.init(1, deskey);
			return c1.doFinal(src);
		} catch (NoSuchAlgorithmException e1) {
			e1.printStackTrace();
		} catch (NoSuchPaddingException e2) {
			e2.printStackTrace();
		} catch (Exception e3) {
			e3.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 3DES解密
	 * @param byte[]  	密匙
	 * @param byte[]	密文
	 * @return byte[]
	 */
	public static byte[] decryptMode(byte[] keybyte, byte[] src) {
		try {
			SecretKey deskey = new SecretKeySpec(keybyte, Algorithm);
			Cipher c1 = Cipher.getInstance(Algorithm);
			c1.init(2, deskey);
			return c1.doFinal(src);
		} catch (NoSuchAlgorithmException e1) {
			e1.printStackTrace();
		} catch (NoSuchPaddingException e2) {
			e2.printStackTrace();
		} catch (Exception e3) {
			e3.printStackTrace();
		}
		return null;
	}
	/**
	 * 字节流数据转为十六进制字符
	 * @param byte[]  		字节流数据
	 * @return String
	 */
	public static String byte2hex(byte[] b) {
		String spliter="";
		String hs = "";
		String stmp = "";
		for (int n = 0; n < b.length; n++) {
			stmp = Integer.toHexString(b[n] & 0xFF);
			if (stmp.length() == 1)
				hs = hs + "0" + stmp;
			else {
				hs = hs + stmp;
			}
			if (n < b.length - 1) {
				hs = hs + spliter;
			}
		}
		return hs.toUpperCase();
	}
	/**
	 * 字节流数据转为十六进制字符
	 * @param byte[]  		字节流数据
	 * @param spliter		分隔符，一般使用空""，解密时只能使用空，输出可以为其他分隔符
	 * @return String
	 */
	public static String byte2hex(byte[] b, String spliter) {
		String hs = "";
		String stmp = "";
		for (int n = 0; n < b.length; n++) {
			stmp = Integer.toHexString(b[n] & 0xFF);
			if (stmp.length() == 1)
				hs = hs + "0" + stmp;
			else {
				hs = hs + stmp;
			}
			if (n < b.length - 1) {
				hs = hs + spliter;
			}
		}
		return hs.toUpperCase();
	}

	/**
	 * 十六进制字符串转为字节流数据
	 * @param String   		十六进制字符串
	 * @return byte[]
	 */
	public static byte[] hex2byte(String hexString) {
		if ((null == hexString) || (hexString.equals(""))) {
			return null;
		}
		hexString = hexString.toUpperCase();
		int length = hexString.length() / 2;
		char[] hexChars = hexString.toCharArray();
		byte[] d = new byte[length];
		for (int i = 0; i < length; i++) {
			int pos = i * 2;
			d[i] = ((byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[(pos + 1)])));
		}
		return d;
	}
	/**
	 * 十六进制字符转为字节流
	 * @param char  		十六进制字符
	 * @return byte
	 */
	private static byte charToByte(char c) {
		return (byte) "0123456789ABCDEF".indexOf(c);
	}
	
	public static void main(String[] args) {
		Security.addProvider(new SunJCE());
		String key="12345678";//加密密匙
		//补0后24位密匙：123456780000000000000000
		byte[] keyBytes = { 49, 50, 51, 52, 53, 54, 55, 56, 48, 48, 48, 48, 48,
				48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 };

		String src = "0010919901049000154938FACAD7A76B";
		System.out.println("src:" + src);
		System.out.println("key:" + key);

		byte[] encoded = encryptMode(keyBytes, src.getBytes());
		String encodedStr = byte2hex(encoded, "-");
		System.out.println("encoded:" + encoded);
		System.out.println("encodedStr:" + encodedStr);
		encodedStr = byte2hex(encoded, "");
		System.out.println("encodedStr:" + encodedStr);
		
		byte[] decoded = decryptMode(keyBytes, encoded);
		String decodedStr = byte2hex(decoded, "");
		System.out.println("decoded:" + decoded);
		System.out.println("decodedStr:" + decodedStr);
		decodedStr = byte2hex(decoded);
		System.out.println("decodedStr:" + decodedStr);

		System.out.println("encrypt3DES:" + encrypt3DES(key, src));
		System.out.println("decrypt3DES:" + decrypt3DES(key, encodedStr));

		key="888888"; //加密密匙
		src = "aaa"; //待加密字符串
		System.out.println("待加密字符串:" + src);
		String encryptStr = encrypt3DES(key, src);
		String decryptStr = decrypt3DES(key, encryptStr);
		System.out.println("加密密匙:" + key);
		System.out.println("加密前字符串:" + src);
		System.out.println("加密后字符串:" + encryptStr);
		System.out.println("解密后字符串:" + decryptStr);
		//对比oracle:9B990BFC31428A5D
		
		key="shangrila";
		src = "aaa"; 
		encryptStr = encrypt3DES(key, src);
		decryptStr = decrypt3DES(key, encryptStr);
		System.out.println("加密密匙:" + key);
		System.out.println("加密前字符串:" + src);
		System.out.println("加密后字符串:" + encryptStr);
		System.out.println("解密后字符串:" + decryptStr);
		//对比oracle:FB81B6CAAFEC9565

		key="dfyc_2017";
		src = "shangrila"; 
		encryptStr = encrypt3DES(key, src);
		decryptStr = decrypt3DES(key, encryptStr);
		System.out.println("加密密匙:" + key);
		System.out.println("加密前字符串:" + src);
		System.out.println("加密后字符串:" + encryptStr);
		System.out.println("解密后字符串:" + decryptStr);

	}

} 